#ifndef FEATURES_STAR_SCARF_H
#define FEATURES_STAR_SCARF_H

#include <opencv/cv.h>
#include <cmath>
#include <fstream>
#include <iostream>
#include <vector>
#include <tmmintrin.h>
#include <cvd/vision.h>

const float pi = float(CV_PI);
const unsigned int num_bins = 72, window_width = 12, num_center = 16, num_inner = 144, num_outer = 216, desc_len = 60;
const float step = (float)num_bins/360;
const float bin_cos[72] = 
{1,0.996194698091746,0.984807753012208,0.965925826289068,0.939692620785908,0.906307787036650,0.866025403784439,0.819152044288992,0.766044443118978,0.707106781186548,0.642787609686539,0.573576436351046,0.500000000000000,0.422618261740699,0.342020143325669,0.258819045102521,0.173648177666930,0.0871557427476581,6.12323399573677e-17,-0.0871557427476582,-0.173648177666930,-0.258819045102521,-0.342020143325669,-0.422618261740699,-0.500000000000000,-0.573576436351046,-0.642787609686539,-0.707106781186548,-0.766044443118978,-0.819152044288992,-0.866025403784439,-0.906307787036650,-0.939692620785908,-0.965925826289068,-0.984807753012208,-0.996194698091746,-1,-0.996194698091746,-0.984807753012208,-0.965925826289068,-0.939692620785908,-0.906307787036650,-0.866025403784439,-0.819152044288992,-0.766044443118978,-0.707106781186548,-0.642787609686540,-0.573576436351046,-0.500000000000000,-0.422618261740699,-0.342020143325669,-0.258819045102521,-0.173648177666930,-0.0871557427476583,-1.83697019872103e-16,0.0871557427476579,0.173648177666930,0.258819045102520,0.342020143325669,0.422618261740700,0.500000000000000,0.573576436351046,0.642787609686539,0.707106781186547,0.766044443118978,0.819152044288992,0.866025403784438,0.906307787036650,0.939692620785908,0.965925826289068,0.984807753012208,0.996194698091746};
const float bin_sin[72] = 
{0,0.0871557427476582,0.173648177666930,0.258819045102521,0.342020143325669,0.422618261740699,0.500000000000000,0.573576436351046,0.642787609686539,0.707106781186548,0.766044443118978,0.819152044288992,0.866025403784439,0.906307787036650,0.939692620785908,0.965925826289068,0.984807753012208,0.996194698091746,1,0.996194698091746,0.984807753012208,0.965925826289068,0.939692620785908,0.906307787036650,0.866025403784439,0.819152044288992,0.766044443118978,0.707106781186548,0.642787609686540,0.573576436351046,0.500000000000000,0.422618261740700,0.342020143325669,0.258819045102521,0.173648177666930,0.0871557427476582,1.22464679914735e-16,-0.0871557427476579,-0.173648177666930,-0.258819045102521,-0.342020143325669,-0.422618261740699,-0.500000000000000,-0.573576436351046,-0.642787609686539,-0.707106781186548,-0.766044443118978,-0.819152044288992,-0.866025403784439,-0.906307787036650,-0.939692620785908,-0.965925826289068,-0.984807753012208,-0.996194698091746,-1,-0.996194698091746,-0.984807753012208,-0.965925826289068,-0.939692620785908,-0.906307787036650,-0.866025403784439,-0.819152044288992,-0.766044443118978,-0.707106781186548,-0.642787609686540,-0.573576436351047,-0.500000000000000,-0.422618261740699,-0.342020143325669,-0.258819045102521,-0.173648177666930,-0.0871557427476583};
const float outer_weight[17] ={0.184202776812482,0.222113261785824,0.261225577534895,0.299653805331177,0.335263895963132,0.365861464748285,0.389412099219778,0.404264033257225,0.409339504027737,0.404264033257225,0.389412099219778,0.365861464748285,0.335263895963132,0.299653805331177,0.261225577534895,0.222113261785824,0.184202776812482};
const float inner_weight[19] = {0.246490113505888,0.291462082518389,0.337910719061368,0.384113188927176,0.428108466019911,0.467827513045169,0.501250764625728,0.526576754033733,0.542382494367207,0.547755807790863,0.542382494367207,0.526576754033733,0.501250764625728,0.467827513045169,0.428108466019911,0.384113188927176,0.337910719061368,0.291462082518389,0.246490113505888};
const float ori_weight[13] = {0.882496902584596,0.535261428518990,0.324652467358350,0.286504796860190,0.196911675204194,0.135335283236613,0.119432968266720,0.105399224561864,0.0820849986238988,0.0439369336234074,0.0387742078317220,0.0142642339089993,0.0111089965382423};

class Scarf
{
public:
  //! Constructor. The dimensions of the source images that will be used
  //! with the detector are required to pre-allocate memory.
  Scarf(const CvSize size);
  Scarf(const CVD::ImageRef size);
  ~Scarf();
  
  void LoadImage(const IplImage* source);
  void LoadImage(CVD::Image<CVD::byte> &source);
  bool DescribePoint(const int x, const int y, const int scale, uint8_t descriptor[64]);

private:
  //! Scale/spatial dimensions
  int m_W, m_H;
  //! Normal integral image
  IplImage* m_upright;
  IplImage* m_source;

  int center_haar_x[num_center];
  int center_haar_y[num_center];
  float inner_haar_x[num_inner];
  float inner_haar_y[num_inner];
  float outer_haar_x[num_outer];
  float outer_haar_y[num_outer];
  float ori_x[num_bins];
  float ori_y[num_bins];
  float desc[desc_len];

  void ZeroOrientation();
  void HaarXY(int &haarx, int &haary, const int x, const int y, const int s);
  void HaarXYO(int &haarx, int &haary, const int x, const int y, const int s, const float weight);
  void HaarXtYt(float &haarx, float &haary, const int x, const int y, const int s, const int t);
  void HaarXtYtO(float &haarx, float &haary, const int x, const int y, const int s, const int t, const float weight);

  //! Calculate the Haar X & Y responses at (x,y) within a circular radius of size 15*s
  void DescriptorResponsesGen2(int x, int y);
  void DescriptorResponsesGen3(int x, int y);
  void DescriptorResponsesGen4(int x, int y);
  void DescriptorResponsesGen5(int x, int y);
  void DescriptorResponsesGen6(int x, int y);
  void DescriptorResponsesGen7(int x, int y);
  void DescriptorResponsesGen8(int x, int y);
  void DescriptorResponsesGen9(int x, int y);
  void DescriptorResponsesGen10(int x, int y);
  void DescriptorResponsesGen11(int x, int y);
  void DescriptorResponsesGen12(int x, int y);
  void DescriptorResponsesGen16(int x, int y);

  int DescriptorDistanceSAD(uint8_t *desc1, uint8_t *desc2);
};


#endif
